﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp.Dependency;
using Castle.Core.Logging;

namespace Abp.Rebus.Data
{
    public abstract class BulkInsertDataBase<T> : ISingletonDependency, IDisposable
    {

        public ILogger Logger { set; get; }


        protected BulkInsertDataBase()
        {
            Queue = new Queue<T>();
            Stopwatch = new Stopwatch();
        }



        #region public method

        /// <summary>
        /// 加入消息到容器中
        /// </summary>
        /// <param name="message"></param>
        public void AddToQueue(T message)
        {
            this.Queue.Enqueue(message);
            if (!IsFitCondition())
                return;
            InsertData(Queue.ToArray());
            Queue.Clear();
            Stopwatch.Reset();
        }


        /// <summary>
        /// 立即执行插入操作
        /// </summary>
        /// <param name="messages"></param>
        public void InsertData(IEnumerable<T> messages)
        {

            var conn = ConnectStr;
            using (var connection = new SqlConnection(conn))
            {
                connection.Open();
                AutoCreateTable(connection);
                InsertDataUsingSqlBulkCopy(messages, connection);

            }
        }

        #endregion

        #region  protected Mothod


        protected bool IsFitCondition()
        {
            if (!Stopwatch.IsRunning)
                Stopwatch.Start();
            return NeedInsert;
        }


        protected virtual void AutoCreateTable(SqlConnection connection)
        {
            string sql = @"IF NOT EXISTS( select * from sysobjects where name='{0}')
                             CREATE TABLE {0}
                             (
                                {1}
	                            )";
            sql = string.Format(sql, TableName, TableDefinition);
            SqlCommand command = new SqlCommand(sql, connection);
            command.ExecuteNonQuery();
        }


        protected void InsertDataUsingSqlBulkCopy(IEnumerable<T> messages, SqlConnection connection)
        {


            var bulkCopy = new SqlBulkCopy(connection);
            bulkCopy.DestinationTableName = TableName;
            if (TableDefinition != null)
            {
                foreach (var item in SqlColumnsCollection)
                {
                    bulkCopy.ColumnMappings.Add(item.Key, item.Value);
                }
            }
            using (var dataReader = new ObjectDataReader<T>(messages))
            {
                bulkCopy.WriteToServer(dataReader);
            }

        }


        protected Queue<T> Queue { get; set; }

        protected Stopwatch Stopwatch { set; get; }


        /// <summary>
        /// 连接字符串
        /// </summary>
        protected abstract string ConnectStr { get; }

        /// <summary>
        /// 表结构定义
        /// </summary>
        protected abstract string TableDefinition { get; }

        /// <summary>
        /// 表名生成规章
        /// </summary>
        protected abstract string TableName { get; }

        /// <summary>
        /// 表名和字段映射规则
        /// </summary>
        protected abstract Dictionary<string, string> SqlColumnsCollection { get; }



        protected virtual bool NeedInsert
        {
            get
            {
                long ticks = Stopwatch.ElapsedMilliseconds;
                if (ticks / 1000 >= 30 || Queue.Count >= 100)
                {
                    return true;
                }
                return false;
            }
        }


        #endregion


        public void Dispose()
        {
            if (Queue.Count > 0)
            {
                InsertData(Queue.ToArray());
            }
        }
    }
}
